﻿using System;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;

namespace Beaker.Injection
{
	/// <summary>
	/// Allows building the container before it gets locked down for querying.
	/// </summary>
	[ContractClass(typeof(ContainerBuilderContracts))]
	public interface IContainerBuilder
	{
		/// <summary>
		/// Register a single concrete type
		/// </summary>
		/// <typeparam name="TConcrete">The concrete type to register</typeparam>
		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void Register<TConcrete>()
			where TConcrete : class;

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void Register<TService, TImplementation>()
			where TService : class
			where TImplementation : class, TService;

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void Register<TService>(Func<TService> instanceCreator)
			where TService : class;

		void Register(Type concreteType);

		void Register(Type serviceType, Type implementation);

		void Register(Type serviceType, Func<object> instanceCreator);

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterSingleton<TConcrete>()
			where TConcrete : class;

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterSingleton<TService, TImplementation>()
			where TService : class
			where TImplementation : class, TService;

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterSingleton<TService>(TService instance)
			where TService : class;

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterSingleton<TService>(Func<TService> instanceCreator)
			where TService : class;

		void RegisterSingleton(Type serviceType, Type implementation);

		void RegisterSingleton(Type serviceType, Func<object> instanceCreator);

		void RegisterSingleton(Type serviceType, object instance);

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterAnother<TService, TImplementation>()
			where TService : class;

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterAnotherSingleton<TService, TImplementation>()
			where TService : class;

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterAnother<TService>(Type implementation)
			where TService : class;

		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterAnotherSingleton<TService>(Type implementation)
			where TService : class;

		/// <summary>
		/// Get the physical underlying container, depending on the DI framework you are using
		/// </summary>
		object PhysicalContainer { get; }

		/// <summary>
		/// Maps a base interface to a specific implementation of interface.
		/// </summary>
		/// <typeparam name="TBase">The base interface to user might request.</typeparam>
		/// <typeparam name="TSpecific">The actual specific interface that will be Injected.</typeparam>
		[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "This design was explicitly chosen.")]
		void RegisterDefault<TBase, TSpecific>()
			where TBase : class
			where TSpecific : class, TBase;

	}

	/// <summary>
	/// Code Contracts for the <see cref="IContainerBuilder"/> interface.
	/// </summary>
	[ContractClassFor(typeof(IContainerBuilder))]
	abstract class ContainerBuilderContracts
		: IContainerBuilder
	{
		public void Register<TConcrete>() where TConcrete : class
		{
			throw new NotImplementedException();
		}

		public void Register<TService, TImplementation>()
			where TService : class
			where TImplementation : class, TService
		{
			throw new NotImplementedException();
		}

		public void Register<TService>(Func<TService> instanceCreator) where TService : class
		{
			Contract.Requires<ArgumentNullException>(instanceCreator != null, "instanceCreator");
			throw new NotImplementedException();
		}

		public void Register(Type concreteType)
		{
			Contract.Requires<ArgumentNullException>(concreteType != null, "concreteType");
			throw new NotImplementedException();
		}

		public void Register(Type serviceType, Type implementation)
		{
			Contract.Requires<ArgumentNullException>(serviceType != null, "serviceType");
			Contract.Requires<ArgumentNullException>(implementation != null, "implementation");
			throw new NotImplementedException();
		}

		public void Register(Type serviceType, Func<object> instanceCreator)
		{
			Contract.Requires<ArgumentNullException>(serviceType != null, "serviceType");
			Contract.Requires<ArgumentNullException>(instanceCreator != null, "instanceCreator");
			throw new NotImplementedException();
		}

		public void RegisterSingleton<TConcrete>() where TConcrete : class
		{
			throw new NotImplementedException();
		}

		public void RegisterSingleton<TService, TImplementation>()
			where TService : class
			where TImplementation : class, TService
		{
			throw new NotImplementedException();
		}

		public void RegisterSingleton<TService>(TService instance) where TService : class
		{
			Contract.Requires<ArgumentNullException>(instance != null, "instance");
			throw new NotImplementedException();
		}

		public void RegisterSingleton<TService>(Func<TService> instanceCreator) where TService : class
		{
			Contract.Requires<ArgumentNullException>(instanceCreator != null, "instanceCreator");
			throw new NotImplementedException();
		}

		public void RegisterSingleton(Type serviceType, Type implementation)
		{
			Contract.Requires<ArgumentNullException>(serviceType != null, "serviceType");
			Contract.Requires<ArgumentNullException>(implementation != null, "implementation");
			throw new NotImplementedException();
		}

		public void RegisterSingleton(Type serviceType, Func<object> instanceCreator)
		{
			Contract.Requires<ArgumentNullException>(serviceType != null, "serviceType");
			Contract.Requires<ArgumentNullException>(instanceCreator != null, "instanceCreator");
			throw new NotImplementedException();
		}

		public void RegisterSingleton(Type serviceType, object instance)
		{
			Contract.Requires<ArgumentNullException>(serviceType != null, "serviceType");
			Contract.Requires<ArgumentNullException>(instance != null, "instance");
			throw new NotImplementedException();
		}

		public void RegisterAnother<TService, TImplementation>()
			where TService : class
		{
			throw new NotImplementedException();
		}

		public void RegisterAnotherSingleton<TService, TImplementation>() where TService : class
		{
			throw new NotImplementedException();
		}

		public void RegisterAnother<TService>(Type implementation)
			where TService : class
		{
			Contract.Requires<ArgumentNullException>(implementation != null, "implementation");
			throw new NotImplementedException();
		}

		public void RegisterAnotherSingleton<TService>(Type implementation) where TService : class
		{
			Contract.Requires<ArgumentNullException>(implementation != null, "implementation");
			throw new NotImplementedException();
		}

		public void RegisterAnother<TService>(TService instance)
			where TService: class
		{
			Contract.Requires<ArgumentNullException>(instance != null, "instance");
			throw new NotImplementedException();
		}

		public void RegisterAnotherSingleton<TService>(TService instance) where TService : class
		{
			Contract.Requires<ArgumentNullException>(instance != null, "instance");
			throw new NotImplementedException();
		}

		public object PhysicalContainer
		{
			get
			{
				Contract.Ensures(Contract.Result<object>() != null);
				throw new NotImplementedException();
			}
		}

		public void RegisterDefault<TBase, TSpecific>()
			where TBase : class
			where TSpecific : class, TBase
		{
			throw new NotImplementedException();
		}
	}

}
